package com.xiangyun.test.utils;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;



public class RSAUtils {
	//加密算法RSA
	public static final String KEY_ALGORITHM = "RSA";
	//签名算法
	public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
	//从map中获取公钥的key
	private static final String PRIVATE_KEY = "RSAtestprivatekey";
	//从map中获取私钥的key
	private static final String PUBLIC_KEY = "RSAtestpublickey";
	//RSA最大加密密文长度
	private static final int MAX_ENCRYPT_BLOCK = 117;
	//RSA最大解密密文长度
	private static final int MAX_DECRYPT_BLOCK = 128;
	//RSA位数
	private static final int INITIALIZE_LENGTH = 1024;
	
	private static final String RSAPIVATE_KEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJD/YAX9k1/+rhskToZE7/599LJCUtJmM8qj6uNRd4Qh7l5R+RvbLFFl9ndXQT41K1pTlTNVAuyI3CtRdfY0lytW13ZG64AZCjxcAx3uUeIvAJc54toAjfNznABMj5FAXr/M143fAfvhB2smOLxyY7is4mUzPsGVMZA9CSpLCqOXAgMBAAECgYEAisj1FybMzkBOU8pfouMPN+9FrO4QqjSK9DYLWMOcewujRgJ+Rux1MgA/daE94JYxxcZk8/o1z0N8QbY6C4vw+Gha/yvCqbF7bvo5KOFaGLEnyPvsqYEvLFSoi/VuE060x+2VIqmdyYWIGw9KTkYB53pGrL4W2WJTDoWduVCFyPECQQDKy1CmtUF8W6+GFO9Inr791I+oKUTxo++I86VICPLPa8tbae+tc2uPMQ8nmiXr4SmbdlVAIndUZuXY3xZAk3rJAkEAtwolJjrmMhBgAsbGc7P0GIQ1S2Kss0zNmDFCiRtQHEiFAz9xqHsYujUimvV1fPKHUDZlflId/DpwHHWZLQX7XwJANuy2HVC+OcZDVddZr5t/MxRdDDiRObki6T7EJyx1RwR1AX9BsQKvwQqShjFTz/0d3cNA96veEfgEjKZvSnInMQJBAJEM4hmkrU1ZOqyYlyWToslW4+EEpjVElNyZlM+QLHDtazMCsPBB9HuDphPElsFYdLC1GsL7EjYSnUuASc2rIuMCQQCov6OfTONon7yRH9B0OMbImCcFNu+ivxqwUnZIONPKsSgivdpU2NqsZaYpUvOIkpPu3a/9LuPJSCarFlS7sv1y";
	
	private static final String RSAPUBLIC_KEY =	"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQ/2AF/ZNf/q4bJE6GRO/+ffSyQlLSZjPKo+rjUXeEIe5eUfkb2yxRZfZ3V0E+NStaU5UzVQLsiNwrUXX2NJcrVtd2RuuAGQo8XAMd7lHiLwCXOeLaAI3zc5wATI+RQF6/zNeN3wH74QdrJji8cmO4rOJlMz7BlTGQPQkqSwqjlwIDAQAB";
	
	
	
	/**
	 * 生成钥匙对
	 * @return
	 * @throws Exception
	 */
	public static Map<String,Object> getKeyPair() throws Exception{
		KeyPairGenerator keyPair = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPair.initialize(INITIALIZE_LENGTH);
		KeyPair pair = keyPair.generateKeyPair();
		RSAPublicKey pubKey = (RSAPublicKey) pair.getPublic();
		RSAPrivateCrtKey priKey = (RSAPrivateCrtKey) pair.getPrivate();
		Map<String,Object> keyMap = new HashMap<String,Object>();
		keyMap.put(PUBLIC_KEY, pubKey);
		keyMap.put(PRIVATE_KEY, priKey);
		return keyMap;
	}
	
	/**
	 * 用私钥生成数字签名
	 * @param data 已经加密过的数据
	 * @param priKey 私钥(base64编码)
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] data,String priKey) throws Exception {
		byte[] keyBytes = Base64.decodeBase64(priKey);
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey privateKey = factory.generatePrivate(pkcs8EncodedKeySpec);
		Signature instance = Signature.getInstance(SIGNATURE_ALGORITHM);
		instance.initSign(privateKey);
		instance.update(data);
		return Base64.encodeBase64String(instance.sign());
	}
	
	/**
	 * 校验数字签名
	 * @param data	已加密数据
	 * @param pubKey	公钥（base64编码）
	 * @param sign	数字签名
	 * @return
	 * @throws Exception
	 */
	public static boolean verify(byte[] data , String pubKey , String sign) throws Exception {
		byte[] keyBytes = Base64.decodeBase64(pubKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initVerify(publicKey);
		signature.update(data);
		return signature.verify(Base64.decodeBase64(sign));
	}
	
	/**
	 * 私钥解密
	 * @param encryptData	已加密数据
	 * @param priKey	私钥
	 * @return
	 * @throws Exception
	 * 用 MAX_DECRYPT_BLOCK
	 */
	public static byte[] decryptByPriKey(byte[] encryptData , String priKey) throws Exception {
		byte[] base64 = Base64.decodeBase64(priKey);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(base64);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateKey = keyFactory.generatePrivate(keySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE,privateKey);
		int length = encryptData.length;
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		int offset = 0;
		byte[] cache;
		int i = 0;
		while(length - offset > 0) {
			if(length - offset > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptData, offset, MAX_DECRYPT_BLOCK);
			}else {
				cache = cipher.doFinal(encryptData, offset, length-offset);
			}
			outputStream.write(cache, 0, cache.length);
			i++;
			offset = i * MAX_DECRYPT_BLOCK;
		}
		byte[] array = outputStream.toByteArray();
		outputStream.close();
		return array; 
	}
	
	/**
	 * 对公钥进行解密
	 * @param encryptData	已经加密的数据
	 * @param pubKey	公钥（base64编码）
	 * @return
	 * @throws Exception
	 * 用 MAX_DECRYPT_BLOCK
	 */
	public static byte[] decryptByPubKey(byte[] encryptData,String pubKey) throws Exception {
		byte[] base64 = Base64.decodeBase64(pubKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(base64);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicKey = keyFactory.generatePublic(keySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE,publicKey);
		int length = encryptData.length;
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		int offset = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段解密
		while (length - offset > 0) {
			if (length - offset > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptData, offset, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(encryptData, offset, length - offset);
			}
			stream.write(cache, 0, cache.length);
			i++;
			offset = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = stream.toByteArray();
		stream.close();
		return decryptedData;

	}
	
	/**
	 * 公钥加密
	 * @param data	源数据
	 * @param pubKey	公钥（64编码）
	 * @return
	 * @throws Exception
	 * 用MAX_ENCRYPT_BLOCK
	 */
	public static byte[] encryptByPubKey(byte[] data,String pubKey) throws Exception {
		byte[] base64 = Base64.decodeBase64(pubKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(base64);
		KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicKey = factory.generatePublic(keySpec);
		Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		int length = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offset = 0;
		byte[] cache ;
		int i = 0;
		while(length - offset > 0){
			if (length - offset > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data, offset, length - offset);
			}
			out.write(cache, 0, cache.length);
			i++;
			offset = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}
	
	/**
	 * 私钥加密
	 * @param data	源数据
	 * @param priKey	私钥（64编码）
	 * @return
	 * @throws Exception
	 * 用MAX_ENCRYPT_BLOCK
	 */
	public static byte[] encryptByPriKey(byte[] data,String priKey) throws Exception {
		byte[] base64 = Base64.decodeBase64(priKey);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(base64);
		KeyFactory factory = KeyFactory.getInstance(SIGNATURE_ALGORITHM);
		Key privateKey = factory.generatePrivate(keySpec);
		Cipher cipher = Cipher.getInstance(factory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		int length = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offset = 0;
		byte[] cache;
		int i = 0;
		while(length - offset > 0){
			if (length - offset > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data, offset, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data, offset, length - offset);
			}
			out.write(cache, 0, cache.length);
			i++;
			offset = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
		
	}
	
	/**
	 * 获取私钥
	 * @param map
	 * @return
	 */
	public static String getPriKey(Map<String,Object> map) {
		Key key = (Key) map.get(PRIVATE_KEY);
		return Base64.encodeBase64String(key.getEncoded());
	}
	
	/**
	 * 获取公钥
	 * @param map
	 * @return
	 */
	public static String getPubKey(Map<String,Object> map) {
		Key key = (Key) map.get(PUBLIC_KEY);
		return Base64.encodeBase64String(key.getEncoded());
	}
	
	/**
	 * java端公钥加密
	 * @param data
	 * @param pubKey
	 * @return
	 */
	public static String encryptDataOnJava(String data,String pubKey) {
		try {
			data = Base64.encodeBase64String(encryptByPubKey(data.getBytes(), pubKey));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return data;
	}
	
	/**
	 * java端私钥解密
	 * @param data
	 * @param priKey
	 * @return
	 */
	public static String decryptDataOnJava(String data,String priKey) {
		String temp = "";
		
		try {
			byte[] bs = Base64.decodeBase64(data);
			temp = new String(RSAUtils.decryptByPriKey(bs, priKey),"utf-8");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return temp;
	}
	/**
	 * 对密码进行解密
	 */
	public static String decryptPassWord(String passWord) {
		return decryptDataOnJava(passWord,RSAPIVATE_KEY);
	}
	
	/**
	 * 对密码进行加密
	 * @param user
	 * @return
	 */
	public static String encryptPassWord(String passWord) {
		return encryptDataOnJava(passWord,RSAPUBLIC_KEY);
	}
	
	 /**
     * String转公钥PublicKey
     * @param key
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = Base64.decodeBase64(key);
//        		(new BASE64Decoder()).decodeBuffer(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }
 
    /**
     * String转私钥PrivateKey
     * @param key
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = Base64.decodeBase64(key); 
//        		(new BASE64Decoder()).decodeBuffer(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

}
